import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.*;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.get.MultiGetItemResponse;
import org.elasticsearch.action.get.MultiGetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.util.Date;
import java.util.concurrent.ExecutionException;

import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;

@Slf4j
public class ElasticSearchStudy extends BaseTest {

  @Autowired
  private TransportClient transportClient;

  /**
   * Index API   创建索引
   *
   * @description:往指定索引(index)(数据库)的指定类型(type)（表）里面插入文档(document)（记录）,文档的id 初始化为1
   * The index API allows one to index a typed JSON document into a specific index and make it searchable.
   * 索引API允许一个人将一个类型化的JSON文档索引到一个特定的索引中，并使其可搜索。
   * @author :yuanJinZhong
   * @date :2018/8/21-15:54
   */
  @Test
  public void Index_API() throws IOException {
    log.info("获取es操作模板:{}", transportClient);
    IndexResponse response = transportClient.prepareIndex("twitter", "tweet", "1").setSource(jsonBuilder()
      .startObject()
      .field("user", "kimchy")
      .field("postDate", new Date())
      .field("message", "trying out Elasticsearch")
      .endObject()
    ).get();
    log.info("索引名:{}", response.getIndex());
    log.info("分片信息:{}", response.getShardInfo().toString());
    log.info("类型名:{}", response.getType());

    //"方式二*************************************************************"
    String json = "{" +
      "\"user\":\"袁金忠\"," +
      "\"postDate\":\"2013-01-30\"," +
      "\"message\":\"学习Elasticsearch\"" +
      "}";
    response = transportClient.prepareIndex("twitter", "tweet")
      .setSource(json, XContentType.JSON)
      .get();
  }

  /**
   * @description:获取指定索引中的指定类型的id为1 的文档
   * @author :yuanJinZhong
   * @date :2018/8/23-11:21
   */
  @Test
  public void Get_API() {
    GetResponse response = transportClient.prepareGet("twitter", "tweet", "1").get();
    log.info("get索引中的文档:{}", response);
  }

  /**
   * @description:删除“指定索引”下“指定类型”的指定id的文档
   * @author :yuanJinZhong
   * @date :2018/8/23-11:23
   */
  @Test
  public void Delete_API() {
    DeleteResponse response = transportClient.prepareDelete("twitter", "tweet", "1").get();
    log.info("delete索引中的文档:{}", response);

  }

  /**
   * @description:给指定索引指定类型的指定文档 更新（新增一个字段:gender）
   * You can either create an UpdateRequest and send it to the client:
   * 你可以创建一个UpdateRequest并将它发送给客户端：
   * @author :yuanJinZhong
   * @date :2018/8/23-11:49
   */
  @Test
  public void Update_API() throws IOException, ExecutionException, InterruptedException {
    UpdateRequest updateRequest = new UpdateRequest();
    updateRequest.index("twitter");
    updateRequest.type("tweet");
    updateRequest.id("AWVks7r4jqzt92pIl8jE");
    updateRequest.doc(jsonBuilder().startObject().field("gender", "male").endObject());
    transportClient.update(updateRequest).get();
  }

  /**
   * @description:获取多个 指定索引指定类型下的指定id的文档
   * The multi get API allows to get a list of documents based on their index, type and id:
   * 多get API允许根据它们的索引、类型和id获取文档列表：
   * @author :yuanJinZhong
   * @date :2018/8/23-12:08
   */
  @Test
  public void multiGetApi() {
    MultiGetResponse response = transportClient.prepareMultiGet().add("twitter", "tweet", "AWVks7r4jqzt92pIl8jE").add("book", "novel", "2", "4", "6").get();
    for (MultiGetItemResponse multiGetItemResponse : response) {
      GetResponse getResponse = multiGetItemResponse.getResponse();
      if (getResponse.isExists()) {
        log.info("指定索引:{},指定id:{},下的文档{}", getResponse.getIndex(), getResponse.getId(), getResponse.getSourceAsString());
      }
    }
  }

  /**
   * 将操作打包
   *
   * @description:The bulk API allows one to index and delete several documents in a single request. Here is a sample
   * 批量API允许一个人在单个请求中索引和删除多个文档。这是一个示例
   * @author :yuanJinZhong
   * @date :2018/8/23-13:30
   */
  @Test
  public void Bulk_API() throws IOException {
    BulkRequestBuilder bulkRequest = transportClient.prepareBulk();
    //操作一
    bulkRequest.add(transportClient.prepareIndex("twitter", "tweet", "3")
      .setSource(jsonBuilder()
        .startObject()
        .field("user", "kimchy")
        .field("postDate", new Date())
        .field("message", "trying out Elasticsearch")
        .endObject()
      )
    );
    //操作二
    bulkRequest.add(transportClient.prepareIndex("twitter", "tweet", "2")
      .setSource(jsonBuilder()
        .startObject()
        .field("user", "kimchy")
        .field("postDate", new Date())
        .field("message", "another post")
        .endObject()
      )
    );
    //将操作打包获取
    BulkResponse bulkResponse = bulkRequest.get();
    if (bulkResponse.hasFailures()) {
      log.info("失败处理逻辑");
    }
  }

  /**
   * @description:Using Bulk Processor 使用批量处理器
   * The BulkProcessor class offers a simple interface to flush bulk operations automatically based on the number or size of requests, or after a given period.
   * 批量处理器类提供了一个简单的接口，可以根据请求的数量或大小，或者在给定的时间段后自动刷新批量操作。
   * @author :yuanJinZhong
   * @date :2018/8/23-13:56
   */
  @Test
  public void Using_Bulk_Processor() {

    BulkProcessor bulkProcessor = BulkProcessor.builder(transportClient, new BulkProcessor.Listener() {
      @Override
      public void beforeBulk(long executionId, BulkRequest request) {

      }

      @Override
      public void afterBulk(long executionId, BulkRequest request, BulkResponse response) {

      }

      @Override
      public void afterBulk(long executionId, BulkRequest request, Throwable failure) {

      }
    })
      .setBulkActions(10000)
      .setBulkSize(new ByteSizeValue(5, ByteSizeUnit.MB))
      .setFlushInterval(TimeValue.timeValueSeconds(5))
      .setConcurrentRequests(1)
      .setBackoffPolicy(BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100), 3))
      .build();

    // Add your requests
    bulkProcessor.add(new DeleteRequest("twitter", "tweet", "2"));
    //close the bulkProcessor if you don't need it anymore
    bulkProcessor.close();

    SearchResponse response = transportClient.prepareSearch().get();

    log.info("Using Bulk Processor response:{}", response);
  }

  /**
   * @description: Search_API 复杂查询，各种条件查询，索引，类型，词条关键字
   * @author :yuanJinZhong
   * @date :2018/8/23-18:11
   */
  @Test
  public void search_API_Test() {
    SearchResponse response = transportClient.prepareSearch("twitter")
      .setTypes("tweet")
      .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
      .setQuery(QueryBuilders.termQuery("message", "学习"))
//				.setPostFilter(QueryBuilders.rangeQuery("age").from(12).to(18))     // Filter
//				.setFrom(0).setSize(60).setExplain(true)
      .get();
    log.info("Search_API_response:{}", response);


  }


}
